/*
 * 
 *  This file is part of Sourceprojects.org Lycia Copyright 2010 noctarius
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 */
package org.sourceprojects.lycia.internal.resolver;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.sourceprojects.lycia.NamespaceResolver;
import org.sourceprojects.lycia.internal.dom.ResourceResolverResult;
import org.sourceprojects.lycia.internal.dom.ResourceResolverResultImpl;
import org.sourceprojects.lycia.internal.logging.LyciaLoggerWrapper;

/**
 * 
 * @author noctarius
 * @since 0.0.1
 */
public class BasicNamespaceResolver implements NamespaceResolver {
	private static final LyciaLoggerWrapper LOGGER = LyciaLoggerWrapper
			.getLogger(BasicNamespaceResolver.class);

	private final NamespaceResolverHandlerContainer[] containers;
	private final ClassLoader classLoader;

	public BasicNamespaceResolver(
			final NamespaceResolverHandlerContainer[] containers,
			final ClassLoader classLoader) {
		this.containers = new NamespaceResolverHandlerContainer[containers.length];
		System.arraycopy(containers, 0, this.containers, 0, containers.length);
		this.classLoader = classLoader;
	}

	@Override
	@SuppressWarnings("unchecked")
	public ResourceResolverResult getInput(final String type,
			final String namespaceURI, final String publicId,
			final String systemId, final String baseURI) {

		for (final NamespaceResolverHandlerContainer container : containers) {
			if (container.getNamespaceURI().equals(namespaceURI)
					|| container.getNamespaceURI().equals(systemId)) {

				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Redirecting namespace '" + namespaceURI
							+ "' or systemId '" + systemId + "' to '"
							+ container.getRedirectedURI() + "'");
				}

				final InputStream is = getByteStream(container
						.getRedirectedURI());

				final ResourceResolverResultImpl input = new ResourceResolverResultImpl();
				input.setBaseURI(baseURI);
				input.setPublicId(publicId);
				input.setSystemId(systemId);
				input.setByteStream(is);

				return input;
			}
		}

		try {
			final Class<?> lsinputClass = Class
					.forName("org.w3c.dom.ls.LSInput");

			final DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			final DocumentBuilder builder = factory.newDocumentBuilder();
			final Object impl = builder.getDOMImplementation();

			final Method method = impl.getClass().getMethod("createLSInput");
			final Object result = method.invoke(impl);

			Class<? extends ResourceResolverResult> wrapperClass;
			wrapperClass = (Class<? extends ResourceResolverResult>) Class
					.forName("org.sourceprojects.lycia.internal.platform.base.LSInputWrapper");
			final Constructor<? extends ResourceResolverResult> constructor = wrapperClass
					.getConstructor(lsinputClass);

			return constructor.newInstance(result);

		} catch (final ClassCastException e) {
			return new ResourceResolverResultImpl();
		} catch (final ParserConfigurationException e) {
			return new ResourceResolverResultImpl();
		} catch (final ClassNotFoundException e) {
			return new ResourceResolverResultImpl();
		} catch (final SecurityException e) {
			return new ResourceResolverResultImpl();
		} catch (final NoSuchMethodException e) {
			return new ResourceResolverResultImpl();
		} catch (final IllegalArgumentException e) {
			return new ResourceResolverResultImpl();
		} catch (final IllegalAccessException e) {
			return new ResourceResolverResultImpl();
		} catch (final InvocationTargetException e) {
			return new ResourceResolverResultImpl();
		} catch (final InstantiationException e) {
			return new ResourceResolverResultImpl();
		}
	}

	@Override
	public String getNamespaceURI() {
		return null;
	}

	private InputStream getByteStream(final String uri) {
		return classLoader.getResourceAsStream(uri);
	}

	@Override
	public String toString() {
		return "BasicNamespaceResolver [classLoader=" + classLoader
				+ ", containers=" + Arrays.toString(containers) + "]";
	}

	public static class NamespaceResolverHandlerContainer {
		private final String namespaceURI;
		private final String redirectedURI;

		public NamespaceResolverHandlerContainer(final String namespaceURI,
				final String redirectedURI) {
			this.namespaceURI = namespaceURI;
			this.redirectedURI = redirectedURI;
		}

		public String getNamespaceURI() {
			return namespaceURI;
		}

		public String getRedirectedURI() {
			return redirectedURI;
		}

		@Override
		public String toString() {
			return "NamespaceResolverHandlerContainer [namespaceURI="
					+ namespaceURI + ", redirectedURI=" + redirectedURI + "]";
		}

	}
}
